#ifndef __XSTRING_H__
#define __XSTRING_H__

#include "util/util_config.h"
#include <iostream>
#include <sstream>

NS_UTIL_BEGIN
class xstring;

// StringTypeHelper
template<typename T>
class Value2StringHelperT
{
public:
	typedef T value_type;
	static size_t size(const T& val)
	{
		std::stringstream ss;
		ss<<val;
		std::string tmp;
		ss>>tmp;
		return tmp.size()+1;
	}
};

template<>
class Value2StringHelperT<std::string>
{
public:
	typedef const char* value_type;
	static size_t size(const std::string& val)
	{
		return val.size()+1;
	}
};

//
class xstring : public std::string
{
public:
	using std::string::iterator;
	using std::string::const_iterator;
	using std::string::reverse_iterator;
	using std::string::const_reverse_iterator;

	typedef std::string base_type;


public:
	xstring();
	xstring(const xstring& str);
	xstring(const std::string& str);
	xstring(const char* c_str);

public:

	xstring& operator<< (const xstring& str)
	{
		(*this) += std::string(str);
		return *this;
	}
	xstring& operator<< (const std::string& str)
	{
		(*this) += str;
		return *this;
	}
	xstring& operator<< (const char* str)
	{
		(*this) += str;
		return *this;
	}

	template<typename T>
	xstring& operator<< (const T& val)
	{
		std::stringstream ss;
		ss<<val;
		std::string tmp;
		ss>>tmp;
		(*this)+=tmp;
		return *this;
	}

	operator std::string& ()
	{
		return *this;
	}

	operator const std::string& () const
	{
		return *this;
	}

	operator const char* () const
	{
		return c_str();
	}

public:
	// Other Methods
	void lowercase();
	void uppercase();

	// R is a general capacitor class
	// R should have a method 'push_back(xstring | string)'
	template<typename R>
	void split(R& target, const xstring& sep = "\n", bool omit_repspace = true/*Omit continuous sep chars*/)
	{
		size_t offset = 0;
		size_t offset_lst = 0;
		while(1)
		{
			offset = this->find_first_of(sep.c_str(), offset_lst);
			if(offset!=npos)
			{
				xstring tmp = this->substr(offset_lst, offset-offset_lst);
				if(omit_repspace && tmp.empty())
				{
					offset_lst = offset+1;
				}else
				{
					target.push_back(tmp);
					offset_lst = offset+1;
				}
			}else
			{
				target.push_back(this->substr(offset_lst, npos));
				break;
			}
		}
	}

public:
	// Static Methods
	template<typename T1>
	static xstring format(const xstring& fmt, const T1& val)
	{
		size_t bfsz = fmt.size() + Value2StringHelperT<T1>::size(val)+100;
		char* buffer = new char[bfsz];
		
		sprintf_s(buffer, bfsz, fmt.c_str(), Value2StringHelperT<T1>::value_type(val));
		xstring tmp(buffer);
		delete[] buffer;
		return tmp;
	}

	template<typename T1, typename T2>
	static xstring format(const xstring& fmt, const T1& v1, const T2& v2)
	{
		size_t bfsz = fmt.size()
			+ Value2StringHelperT<T1>::size(v1)
			+ Value2StringHelperT<T2>::size(v2)
			+ 100;

		char* buffer = new char[bfsz];
		sprintf_s(buffer, bfsz, fmt.c_str(), Value2StringHelperT<T1>::value_type(v1), Value2StringHelperT<T2>::value_type(v2));
		xstring tmp(buffer);
		delete[] buffer;
		return tmp;
	}
	
	template<typename T1, typename T2, typename T3>
	static xstring format(const xstring& fmt, const T1& v1, const T2& v2, const T3& v3)
	{
		size_t bfsz = fmt.size()
			+ Value2StringHelperT<T1>::size(v1)
			+ Value2StringHelperT<T2>::size(v2)
			+ Value2StringHelperT<T3>::size(v3)
			+ 100;

		char* buffer = new char[bfsz];
		sprintf_s(buffer, bfsz, fmt.c_str(),
			Value2StringHelperT<T1>::value_type(v1),
			Value2StringHelperT<T2>::value_type(v2),
			Value2StringHelperT<T3>::value_type(v3));
		xstring tmp(buffer);
		delete[] buffer;
		return tmp;
	}

	template<typename T1, typename T2, typename T3, typename T4>
	static xstring format(const xstring& fmt, const T1& v1, const T2& v2, const T3& v3, const T4& v4)
	{
		size_t bfsz = fmt.size()
			+ Value2StringHelperT<T1>::size(v1)
			+ Value2StringHelperT<T2>::size(v2)
			+ Value2StringHelperT<T3>::size(v3)
			+ Value2StringHelperT<T4>::size(v4)
			+ 100;

		char* buffer = new char[bfsz];
		sprintf_s(buffer, bfsz, fmt.c_str(),
			Value2StringHelperT<T1>::value_type(v1),
			Value2StringHelperT<T2>::value_type(v2),
			Value2StringHelperT<T3>::value_type(v3),
			Value2StringHelperT<T4>::value_type(v4));
		xstring tmp(buffer);
		delete[] buffer;
		return tmp;
	}

	template<typename T1, typename T2, typename T3, typename T4, typename T5>
	static xstring format(const xstring& fmt, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5)
	{
		size_t bfsz = fmt.size()
			+ Value2StringHelperT<T1>::size(v1)
			+ Value2StringHelperT<T2>::size(v2)
			+ Value2StringHelperT<T3>::size(v3)
			+ Value2StringHelperT<T4>::size(v4)
			+ Value2StringHelperT<T5>::size(v5)
			+ 100;

		char* buffer = new char[bfsz];
		sprintf_s(buffer, bfsz, fmt.c_str(),
			Value2StringHelperT<T1>::value_type(v1),
			Value2StringHelperT<T2>::value_type(v2),
			Value2StringHelperT<T3>::value_type(v3),
			Value2StringHelperT<T4>::value_type(v4),
			Value2StringHelperT<T5>::value_type(v5));
		xstring tmp(buffer);
		delete[] buffer;
		return tmp;
	}

	// Tools
	typedef enum{strip_head, strip_tail, strip_both} strip_mode;
	xstring strip(strip_mode mode = strip_tail)const
	{
		xstring ret;

		static xstring void_char_lst = " \t\b\r\n";

		xstring::size_type s0, s1;
		s0 = 0;
		s1 = this->length()-1;

		if(mode==strip_head || mode==strip_both)
		{
			s0 = this->find_first_not_of(void_char_lst, 0);
		}
		if(mode==strip_tail || mode==strip_both)
		{
			s1 = this->find_last_not_of(void_char_lst, 0);
		}
		ret = this->substr(s0, s1-s0+1);
		return ret;
	}
	
};


template<>
class Value2StringHelperT<xstring>
{
public:
	typedef const char* value_type;
	static size_t size(const xstring& val)
	{
		return val.size()+1;
	}
};



NS_UTIL_END

#endif